package org.repchain;

import cn.hutool.core.io.file.FileReader;
import cn.hutool.http.HttpRequest;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.rcjava.protos.Peer;
import org.apache.commons.lang3.RandomUtils;
import org.yaml.snakeyaml.Yaml;

import java.io.File;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;
import java.util.UUID;

/**
 * Hello world!
 */
public class App {
    // 生产环境
    private static final String host = "http://42.193.105.24/user/";
//    private static final String host = "http://localhost:8082/user/";
//    private static final String host = "http://192.168.2.76:8082/user/";

    public String path = this.getClass().getProtectionDomain().getCodeSource().getLocation().getFile();

    /**
     * 执行主函数
     *
     * @param args
     */
    public static void main(String[] args) {
//         发电还是用电 ，发电：produce ,用电：consume，根据实际情况进行修改
        String electType = args[0];
//        String electType = "consume";
        System.out.println("type:" + electType + ":typeafter");
//         电量（需要根据实际情况进行修改，现在为随机生成）
        String qualityStr = args[1];
//        String qualityStr = "6875898212340068910833333433a95839386e16";
        System.out.println("quality:" + qualityStr + ":quelityafter");
        double quality = getElectric(qualityStr);
        System.out.println("quality_double:" + quality);
//         获取当前jar包路径
        App app = new App();
        String path = app.path.substring(0, app.path.lastIndexOf("/"));
        try {
            boolean flag = valid(qualityStr);
            if (flag) {
                // 获取上一次电量
                double lastQuality = getLastRecord(path, quality,electType);
                double uploadQuality = quality - lastQuality;
                // 上传电量
                uploadData(electType, uploadQuality,path);
                System.out.println("uploadQuality:"+uploadQuality);
            }
            System.out.println("isValid:"+flag);
            // 将最近电量写入文件
            writeNewRecord(path,quality,electType);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    public static boolean valid(String qualityStr) {
        int total = 0;
        for (int i = 0; i < qualityStr.length() - 4; i = i + 2) {
            String sub = qualityStr.substring(i, i + 2);
            total += hexToDecimal(sub.toUpperCase());
        }
        String resultStr = toHexInt(total);
        resultStr = resultStr.substring(resultStr.length() - 2);
        int start = qualityStr.length() - 4;
        int end = start + 2;
        String validStr = qualityStr.substring(start, end);
        System.out.println(resultStr+":"+validStr);
        return validStr.equalsIgnoreCase(resultStr);
    }

    public static double getLastRecord(String path,double quality,String electType) throws IOException {
        String filePath = path + "/last_record_quality_"+electType.trim();
        File file = new File(filePath);
        if (!file.exists()) {
            boolean flag = file.createNewFile();
            if (!flag) {
                throw new RuntimeException("Cannot create files!!!");
            }
        }
        // 获取文件中记录的上一次的时间戳
        String record = FileUtil.readFile(filePath);
        if (record == null||"".equals(record)) {
            return quality;
        }
        return Double.parseDouble(record);
    }

    public static void writeNewRecord(String path, double quality,String electType) {
        String filePath = path + "/last_record_quality_"+electType.trim();
        boolean flag = FileUtil.replaceContentToFile(String.valueOf(quality), filePath);
        if (!flag) {
            throw new RuntimeException("Cannot write a new record to file!!!");
        }
    }

    public static Double getElectric(String string) {
        String countStr = string.substring(18, 20);
        String type = string.substring(16, 18);
        int count = hexToDecimal(countStr);
        if ("91".equals(type)) {
            count = count - 4;
            string = string.substring(28, count * 2 + 28);
        } else {
            count = count - 2;
            string = string.substring(24, count * 2 + 24);
        }
        System.out.println("quality_HEX:"+string);
        int total = 0;
        StringBuilder result = new StringBuilder("");
        for (int i = 0; i < string.length(); i = i + 2) {
            String sub = string.substring(i, i + 2);
            int intResult = hexToDecimal(sub.toUpperCase()) - hexToDecimal("33");
            result.insert(0, toHexInt(intResult));
            if (i == 0) {
                result.insert(0, ".");
            }
        }
        if (result.toString().startsWith(".")) {
            result.insert(0, "0");
        }
        return Double.parseDouble(result.toString());
    }

    /**
     * @return void
     * @author lhc
     * @description // 上传电量方法
     * @date 3:19 下午 2021/8/20
     * @params [electType, quality, path]
     **/
    public static void uploadData(String electType, Double quality, String path) {
        // 从yml读取用户信息，并构造用户信息类（证书，用户名，私钥，证书名，token）
        SysCert sysCert = readYaml(path);
        // 设置访问地址
        String url = sysCert.getHost() + "electric/get";
        // 自动生成唯一主键
        String uuid = UUID.randomUUID().toString().replaceAll("-", "");
        // 从电量系统获取时间区间ID
        String internalId = getInternalTimeId(path);
        sysCert.setCert(handleCert(sysCert.getCert()));
        sysCert.setPrivateKey(handlePrivateKey(sysCert.getPrivateKey()));
        System.out.println(sysCert);
        // 构造需要签名的电量对象
        ElectricReCharge charge = new ElectricReCharge(internalId, electType, quality, uuid, sysCert.getCreditCode());
        // 对电量对象数据进行签名
        Peer.Transaction tran = ElectricClientUtil.buildContract(JSON.toJSONString(charge), "chargeElectricity", sysCert);
        // 构造Post请求参数
        Map<String, Object> map = new HashMap<>(2);
        map.put("electType", electType);
        map.put("quality", quality);
        map.put("electDealId", uuid);
        map.put("internalTimeId", internalId);
        map.put("electTran", HexUtil.bytesToHex(tran.toByteArray()));
        // 发送电量请求
        String result = HttpRequest.post(url)
                .header("gateway-token", sysCert.getToken())
                .form(map)
                .timeout(20000)
                .execute().body();
        System.out.println(result);
    }

    /**
     * @return org.repchain.SysCert
     * @author lhc
     * @description //读取yml文件内容
     * @date 3:20 下午 2021/8/20
     * @params [path]
     **/
    public static SysCert readYaml(String path) {
        Yaml yaml = new Yaml();
        FileReader fileReader = new FileReader(path + "/app.yml");
        return yaml.loadAs(fileReader.getInputStream(), SysCert.class);
    }

    /**
     * @return java.lang.String
     * @author lhc
     * @description // 获取时间区间ID
     * @date 3:20 下午 2021/8/20
     * @params []
     **/
    private static String getInternalTimeId(String path) {
        // 从yml读取用户信息，并构造用户信息类（证书，用户名，私钥，证书名，token）
        SysCert sysCert = readYaml(path);
        String url = sysCert.getHost() + "deal/time";
        String result = HttpRequest.get(url)
                .timeout(20000)
                .execute().body();
        System.out.println(result);
        ResultVO resultVO = JSON.parseObject(result, ResultVO.class);
        JSONObject str = (JSONObject) resultVO.getData();
        return (String) str.get("id");
    }

    private static String handleCert(String cert) {
        String start = "-----BEGIN CERTIFICATE-----";
        String end = "-----END CERTIFICATE-----";
        cert = cert.replaceAll(start, "");
        cert = cert.replaceAll(end, "");
        cert = cert.replaceAll(" ", "\n");
        return start + cert + end + "\n";
    }

    private static String handlePrivateKey(String privateKey) {
        String start = "-----BEGIN PRIVATE KEY-----";
        String end = "-----END PRIVATE KEY-----";
        privateKey = privateKey.replaceAll(start, "");
        privateKey = privateKey.replaceAll(end, "");
        privateKey = privateKey.replaceAll(" ", "\n");
        return start + privateKey + end + "\n";
    }

    /**
     * @param: [hex]
     * @return: int
     * @description: 按位计算，位值乘权重
     */
    public static int hexToDecimal(String hex) {
        int outcome = 0;
        for (int i = 0; i < hex.length(); i++) {
            char hexChar = hex.charAt(i);
            outcome = outcome * 16 + charToDecimal(hexChar);
        }
        return outcome;
    }

    /**
     * @param: [c]
     * @return: int
     * @description 将字符转化为数字
     */
    public static int charToDecimal(char c) {
        if (c >= 'A' && c <= 'F') {
            return 10 + c - 'A';
        } else {
            return c - '0';
        }
    }

    /**
     * 十进制转16进制
     *
     * @param num
     */
    public static String toHexInt(int num) {
        StringBuilder sb = new StringBuilder();
        int temp;
        //转成8位十六进制
        for (int i = 0; i < 8; i++) {
            temp = num & 15;
            if (temp > 9) {
                sb.append((char) (temp - 10 + 'A'));
            } else {
                sb.append(temp);
            }
            num = num >>> 4;
        }
        String result = sb.reverse().toString();
        StringBuilder formatStr = new StringBuilder();
        for (int i = 0; i < result.length(); i++) {
            String sub = result.substring(i, i + 1);
            if (!"0".equals(sub)) {
                formatStr.append(result, i, result.length());
                break;
            }
        }
        return formatStr.toString();
    }
}
